﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Windows.Forms;
using SpeechLib;
using System.Runtime.InteropServices;

namespace douyuBarrage
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
            TextBox.CheckForIllegalCrossThreadCalls = false;//关闭跨线程修改控件检查
            //开启发送弹幕线程
            Thread thread = new Thread(WriteIndexContent);
            thread.IsBackground = true;
            thread.Start();
            //开启弹幕处理线程
            Thread barrageHandleThread = new Thread(barrageHandle);
            barrageHandleThread.IsBackground = true;
            barrageHandleThread.Start();
            timer2.Start();
        }
        const int Prot = 8602;//端口
        static byte[] endByte = { 0x00 };//发送数据结尾字节
        private static byte[] result = new byte[1024];//缓存字节
        public Socket clientSocket;
        public static bool closeTherad = false;//是否关闭线程
        public static bool IsVoice = false;//是否开启语音
        public static int VoiceTime = 10;//语音间隔
        public static string roomIdValue = null;


        #region 窗体拖动代码
        public const int WM_NCLBUTTONDOWN = 0xA1;
        public const int HTCAPTION = 0x2;

        [DllImportAttribute("user32.dll")]
        public static extern int SendMessage(IntPtr hWnd, int Msg, int wParam, int lParam);

        [DllImportAttribute("user32.dll")]
        public static extern bool ReleaseCapture();
        private void Form1_MouseDown(object sender, MouseEventArgs e)
        {
            ReleaseCapture();
            SendMessage(Handle, WM_NCLBUTTONDOWN, HTCAPTION, 0);
        }
        #endregion

        /// <summary>
        /// 确定事件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void button1_Click(object sender, EventArgs e)
        {
            linkSocket();
        }

        #region 链接获取弹幕
        /// <summary>
        /// 获取地址
        /// </summary>
        public void linkSocket()
        {
            //开始
            textBox2.BringToFront();
            if (clientSocket != null)//判断是否是第一次
            {
                closeTherad = true;
                string data2 = "type@=logout/";
                byte[] data2Byte = Encoding.UTF8.GetBytes(data2);
                data2Byte = data2Byte.Concat(endByte).ToArray();
                byte len2 = Convert.ToByte(data2.Length + 9);
                byte[] headByte2 = { len2, 0x00, 0x00, 0x00, len2, 0x00, 0x00, 0x00, 0xb1, 0x02, 0x00, 0x00 };
                data2Byte = headByte2.Concat(data2Byte).ToArray();
                clientSocket.Send(data2Byte, data2Byte.Length, SocketFlags.None);
            }
            IPHostEntry localhost = Dns.GetHostEntry(@"openbarrage.douyutv.com");
            IPAddress localaddr = localhost.AddressList[0];//获取弹幕ip地址
            if (localaddr != null)
            {
                appendError("获取ip地址成功");
                richTextBox1.Text = "";
                //实例化 套接字 
                clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                try
                {
                    clientSocket.Connect(new IPEndPoint(localaddr, Prot)); //链接  配置服务器IP与端口
                }
                catch (Exception ee)
                {
                    appendError("连接服务器失败,错误原因:" + ee.Message);
                    return;
                }
                timer1.Interval = 40000;//定时
                Handshake(clientSocket);
            }
            else
            {
                appendError("获取ip地址失败");
                return;
            }
        }


        /// <summary>
        /// 登录验证
        /// </summary>
        public void Handshake(Socket clientSocket)
        {
            try
            {
                string roomId = textBox1.Text.ToString();
                if (string.IsNullOrWhiteSpace(roomId))
                {
                    appendError("房间号不能为空");
                    return;
                }
                roomIdValue = roomId;
                //第一次
                string data1 = "type@=loginreq/username@qq_fsasa/password@=1234567890123456/roomid@=" + roomId + "/";//发送的内容
                byte[] data1Byte = Encoding.ASCII.GetBytes(data1);
                data1Byte = data1Byte.Concat(endByte).ToArray();//添加结束内容
                byte len1 = Convert.ToByte(data1.Length + 9);
                byte[] headByte = { len1, 0x00, 0x00, 0x00, len1, 0x00, 0x00, 0x00, 0xb1, 0x02, 0x00, 0x00 };
                data1Byte = headByte.Concat(data1Byte).ToArray();//添加头内容
                clientSocket.Send(data1Byte, data1Byte.Length, SocketFlags.None);//发送
                //第二次
                clientSocket.Receive(result);//接收
                //第三次
                string data2 = "type@=joingroup/rid@=" + roomId + "/gid@=-9999/";
                byte[] data2Byte = Encoding.ASCII.GetBytes(data2);
                data2Byte = data2Byte.Concat(endByte).ToArray();
                byte len2 = Convert.ToByte(data2.Length + 9);
                byte[] headByte2 = { len2, 0x00, 0x00, 0x00, len2, 0x00, 0x00, 0x00, 0xb1, 0x02, 0x00, 0x00 };
                data2Byte = headByte2.Concat(data2Byte).ToArray();
                clientSocket.Send(data2Byte, data2Byte.Length, SocketFlags.None);
                appendError("登录房间成功，海量弹幕马上到来");
                this.Text = "斗鱼弹幕 — — " + roomId;
                timer1.Start();//开启计时器
                Thread receiveThread = new Thread(getDanmu);//实例化进程
                receiveThread.Start(clientSocket);//打开获取弹幕进程 带参数

            }
            catch (Exception e)
            {
                appendError("登录房间失败，错误原因：" + e.Message);
                return;
            }
        }

        /// <summary>
        /// 获取弹幕
        /// </summary>
        /// <param name="clientSocket"></param>
        private void getDanmu(object Socket)
        {
            Socket clientSocket = (Socket)Socket;
            richTextBox1.BringToFront();
            richTextBox2.BringToFront();
            closeTherad = false;
            while (true)
            {
                try
                {
                    int receiveLength = clientSocket.Receive(result);//接收数据
                    if (closeTherad)
                    {
                        return;
                    }
                    if (receiveLength < 12 && receiveLength > 0)//判断接收数据是否小于12字节
                    {
                        continue;
                    }
                    string str = Encoding.UTF8.GetString(result, 12, receiveLength - 12);
                    if (BarrageHandle.getType(str) == BarrageHandle.barrageType.error)
                    {
                        //Thread closeT = Thread.CurrentThread;
                        //closeT.Abort();
                        Action ac = new Action(linkSocket);
                        ac.Invoke();
                        return;
                    }
                    BarrageHandle.barrageStr.Enqueue(str);
                }
                catch (Exception e)
                {
                    appendError("获取弹幕失败，错误原因：" + e.Message);
                    Action ac = new Action(linkSocket);
                    ac.Invoke();
                    return;
                }
            }
        }

        #endregion


        /// <summary>
        /// 心跳包
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void timer1_Tick(object sender, EventArgs e)
        {
            //unix时间戳
            try
            {
                DateTime dtStart = TimeZone.CurrentTimeZone.ToLocalTime(new DateTime(1970, 1, 1));
                DateTime dtNow = DateTime.Parse(DateTime.Now.ToString());
                TimeSpan toNow = dtNow.Subtract(dtStart);
                string timeStamp = toNow.Ticks.ToString();
                timeStamp = timeStamp.Substring(0, timeStamp.Length - 7);
                //发送心跳包
                string data = "type@=keeplive/tick@=" + timeStamp + "/";
                byte[] dataByte = Encoding.ASCII.GetBytes(data);
                dataByte = dataByte.Concat(endByte).ToArray();
                byte len = Convert.ToByte(data.Length + 9);
                byte[] headByte = { len, 0x00, 0x00, 0x00, len, 0x00, 0x00, 0x00, 0xb1, 0x02, 0x00, 0x00 };
                dataByte = headByte.Concat(dataByte).ToArray();
                clientSocket.Send(dataByte, dataByte.Length, SocketFlags.None);
            }
            catch (Exception ee)
            {
                textBox2.AppendText("心跳包发送失败,原因:" + ee.Message);
                Action ac = new Action(linkSocket);
                ac.Invoke();
            }
        }

        /// <summary>
        /// 关闭窗体
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Form1_FormClosing(object sender, FormClosingEventArgs e)
        {
            if (clientSocket != null)
            {
                clientSocket.Close();
            }
            System.Environment.Exit(0);
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            //trackBar1.Enabled = false;
        }

        /// <summary>
        /// 切换显示信息
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void button3_Click(object sender, EventArgs e)
        {
            string txt = button3.Text.ToString();
            if (txt == "显示提示信息")
            {
                textBox2.BringToFront();
                button3.Text = "显示聊天信息";
            }
            else
            {
                richTextBox1.BringToFront();
                richTextBox2.BringToFront();
                button3.Text = "显示提示信息";
            }
        }

        /// <summary>
        /// 开关滚动
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void button4_Click(object sender, EventArgs e)
        {
            bool getAutoSelect = richTextBox1.HideSelection;
            if (getAutoSelect == true)
            {
                richTextBox1.HideSelection = false;
                button4.Text = "关闭滚动";
            }
            else
            {
                richTextBox1.HideSelection = true;
                button4.Text = "开启滚动";
            }
        }

        /// <summary>
        /// 是否显示于顶层
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void checkBox2_CheckedChanged(object sender, EventArgs e)
        {
            this.TopMost = checkBox2.Checked;
        }

        /// <summary>
        /// 发送弹幕到服务器线程
        /// </summary>
        private void WriteIndexContent()
        {
            while (true)
            {
                if (sendContent.queue.Count > 0)
                {
                    sendContent.send();
                }
                else
                {
                    Thread.Sleep(3000);
                }
            }
        }

        /// <summary>
        /// 处理弹幕线程
        /// </summary>
        private void barrageHandle()
        {
            BarrageHandle b = new BarrageHandle(this);
            while (true)
            {
                if (BarrageHandle.barrageStr.Count > 0)
                    b.handleBarrage();
                else
                    Thread.Sleep(1);
            }
        }

        /// <summary>
        /// 设置
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void button2_Click(object sender, EventArgs e)
        {
            Setting set = new Setting();
            set.ShowDialog();
        }

        #region 向文本框输入内容
        /// <summary>
        /// 定时清空textbox
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void timer2_Tick(object sender, EventArgs e)
        {
            richTextBox1.Text = "";
            richTextBox2.Text = "";
            //textBox2.Text = "";
        }

        /// <summary>
        /// 插入用户聊天消息
        /// </summary>
        /// <param name="name"></param>
        /// <param name="text"></param>
        /// <param name="color"></param>
        public void appendChatmsg(string name, string text, Color color)
        {
            richTextBox1.AppendText("\r\n");
            appendRichTextBox(name + ":", Color.Blue);
            appendRichTextBox(text, color);

        }

        /// <summary>
        /// 插入用户进房消息
        /// </summary>
        /// <param name="name"></param>
        public void appendUenter(string name)
        {
            richTextBox1.AppendText("\r\n");
            appendRichTextBox(string.Format("\"{0}\" 进入房间", name), Color.Red);
            //richTextBox1.SelectionColor = Color.Blue;
            //richTextBox1.AppendText(name + "：");
        }

        /// <summary>
        /// 插入礼物消息
        /// </summary>
        /// <param name="name">用户名</param>
        /// <param name="gfid">礼物id</param>
        /// <param name="gfcnt">礼物个数</param>
        /// <param name="hits">礼物连击数</param>
        public void appendDgb(string name, string gfid, string gfcnt, string hits)
        {
            string lastText = name + " 赠送 " + gfid + " x";
            if (richTextBox2.Text.IndexOf(lastText) != -1)
            {
                richTextBox2.SelectionStart = richTextBox2.Text.IndexOf(lastText) - 1;
                richTextBox2.SelectionLength = lastText.Length + 7;
                richTextBox2.SelectedText = "";
            }
            richTextBox2.AppendText("\r\n");
            appendRichTextBox2(name, Color.Red);
            appendRichTextBox2(" 赠送 ", Color.Black);
            appendRichTextBox2(gfid, Color.Red);
            appendRichTextBox2(string.Format(" x{0}连击", Convert.ToInt32(hits).ToString().PadLeft(4, ' ')), Color.Black);
            //appendRichTextBox2(string.Format(@"{0} 赠送 {1} ",name, gfid, gfcnt, hits), Color.Red);
        }


        /// <summary>
        /// 向RichTextBox1追加数据
        /// </summary>
        private void appendRichTextBox(string text, Color color)
        {
            richTextBox1.SelectionColor = color;
            richTextBox1.AppendText(text);
        }

        /// <summary>
        /// 向RichTextBox2追加数据
        /// </summary>
        private void appendRichTextBox2(string text, Color color)
        {
            richTextBox2.SelectionColor = color;
            richTextBox2.AppendText(text);
        }
        /// <summary>
        /// 向textBox2写入错误信息
        /// </summary>
        /// <param name="text"></param>
        public void appendError(string text)
        {
            textBox2.AppendText(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + text + "\r\n");
        }
        #endregion
      
    }
}
